'use strict';

let socketIO = require('socket.io');
let mysql = require('./db.js');
const { v4: uuidv4 } = require('uuid');

let SOCKET={};

SOCKET.start=function socketCallBack(app){
    //socket的io实例
    let io = socketIO.listen(app);
    //连接池
    let sockets={};
    //用户信息
    let userInfos={};
    //连接管理器
    let sidAndUid={};
    //房间管理
    let roomManager={};
    //用户和房间关联
    let userAndRoom={};
    //用户平台划分
    let userAndSign={};

    io.sockets.on('connection', function(socket) {
        /**
         * 日志回传
         */
        function log() {
            const array = [];
            array.push.apply(array, arguments);
            console.log('socket['+(new Date()).Format("yyyy-MM-dd hh:mm:ss")+']', array);
        }

        let sign=socket.handshake.headers['auth_sign'];
        if(sign==null){
            sign=socket.handshake.query.auth_sign;
        }
        if(sign==null){
            log('未知设备接入，请先去获取签名')
            socket.emit('signErr','please auth with sign!');
            socket.disconnect();
            return;
        }else{
            mysql.make("select * from signApp where sign='"+sign+"'",function (result) {
                if(result==null||result.length==0){
                    log('签名验证失败，当前用户没有权限登录系统',sign);
                    socket.emit('signErr','sign is err,please check it!');
                    socket.disconnect();
                    return;
                }
            });
        }

        /**
         * 提示用户连接成功，可以注册/重连
         */
        socket.emit('connectSuccess',socket.id);
        /**
         * 用户向服务器注册
         */
        socket.on('online',function (userInfo) {
            //根据房间名获取房间信息
            const id = userInfo['id'];
            const info = userInfo['info'];

            sockets[id]=socket;

            userInfos[id]=info;
            sidAndUid[socket.id]=id;

            let users=userAndSign[sign];
            if(users==null){
                users=[];
            }
            users[users.length]=id;
            userAndSign[sign]=users;

            log('用户'+id+',已经上线');
            log('当前在线用户',userInfos);
            /**
             * 回复用户上线结果
             */
            socket.emit('onlineRev',id);

            /**
             * 回复频道内所有用户通讯录
             */
            io.sockets.emit('getContactsRev',userInfos);
        });
        //重连
        socket.on('toreconnect',function () {
            log("申请重连");
            socket.emit('connectSuccess',socket.id);
        });
        /**
         * 用户断开连接
         */
        socket.on('disconnect',function () {

            log('用户'+sidAndUid[socket.id]+',离线');

            delete sockets[sidAndUid[socket.id]];
            delete userInfos[sidAndUid[socket.id]];
            delete userAndSign[sidAndUid[socket.id]];
            delete sidAndUid[socket.id];
            //解除绑定
            let room=userAndRoom[sidAndUid[socket.id]]
            if(room!=null){
                delete userAndRoom[sidAndUid[socket.id]];
                //刷新房间状态
                let clientsInRoom=io.sockets.adapter.rooms[room];
                let numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
                if(numClients==0){
                    roomManager[room]['status']=1;
                }
            }
            io.sockets.emit('getContactsRev',userInfos);
        });

        /**
         * 用户端若未收到通讯录则主动请求通讯录信息
         */
        socket.on('getContacts',function (id) {
            let soc=sockets[id];
            let contacts={};
            let users=userAndSign[sign];
            for(let index=0;index<users.length;index++){
                let uid=users[index];
                contacts[uid]=userInfos[uid];
            }
            soc.emit('getContactsRev',contacts);
        });
        /**
         * 心跳处理
         */
        socket.on('heart',function (heart) {
            //回复心跳
            socket.emit('heartRev',heart)
        });

        /**
         * 交互信息监听
         */
        socket.on('message', function(message) {
            let to = message['to'];
            let from = message['from'];
            log('from:' + from + " to:" + to, message);

            // let fromRoomId=userAndRoom[from];
            // io.sockets.in(fromRoomId).emit('messageRev',message);

            let soc=sockets[to];

            soc.emit('messageRev', message);

        });

        /**
         * 单呼请求监听
         */
        socket.on('singleCall', function(message) {
            let to = message['to'];
            let from = message['from'];

            let soc=sockets[to];
            let socF=sockets[from];
            //通知客户端已收到单呼请求
            socF.emit('singleCallRev',message)
            if(soc==null){
                log('被叫',to,'不在线');
                socF.emit('unline', to);
            }else{
                let toSign=soc.handshake.headers['auth_sign'];
                if(toSign==null){
                    toSign=soc.handshake.query.auth_sign;
                }
                if(sign!=toSign){
                    log('被叫',to,'不在同一个签名域',toSign);
                    socF.emit('unline', to);
                    return;
                }

                const msg = Object.assign({},message);
                msg['from']=userInfos[from];

                if(userAndRoom[to]!=null){
                    socF.emit('userBusy', to);
                    soc.emit('someBodyCall',msg);
                    return;
                }

                soc.emit('beSingleCall', msg);
            }

            log('用户' + from + '呼叫用户' + to, message);

        });

        /**
         * 呼叫方取消呼叫
         */
        socket.on('closeSingleCall', function(message) {
            let to = message['to'];
            let from = message['from'];

            log("用户："+from+"取消呼叫");

            let soc=sockets[to];
            let socF=sockets[from];

            let roomid=userAndRoom[to];

            if(roomid==null){
                if(soc==null){
                    socF.emit('unline', to);
                }else{
                    let toSign=soc.handshake.headers['auth_sign'];
                    if(toSign==null){
                        toSign=soc.handshake.query.auth_sign;
                    }
                    if(sign!=toSign){
                        socF.emit('unline', to);
                        return;
                    }

                    const msg = Object.assign({},message);
                    msg['from']=userInfos[from];
                    msg['status']='close';

                    soc.emit('someBodyCall',msg);
                    soc.emit('beCloseSingleCall', msg);
                }
            }
        });

        //客户端确定收到被呼叫请求
        socket.on('beSingleCallRev',function (data) {

        });

        /**
         * 多呼请求监听
         */
        socket.on('moreCall', function(message) {
            let tos = Object.assign([],message['to']);
            let from = message['from'];

            // let infoMsg=message;
            // for(let position=0;position<tos.length;position++){
            //     infoMsg['to'][position]=userInfos[tos[position]]
            // }

            log('用户' + from + '发起多人会话', message);

            for(let index=0;index<tos.length;index++){
                let soc=sockets[tos[index]];

                let toSign=soc.handshake.headers['auth_sign'];
                if(toSign==null){
                    toSign=soc.handshake.query.auth_sign;
                }
                if(sign!=toSign){
                    break;
                }

                let newMessage=Object.assign({},message);

                let newTo=Object.assign([],tos);
                newTo[index]=from;
                // newMessage['to'][index]=userInfos[from];
                newMessage['to']=newTo;
                newMessage['from']=userInfos[from];

                if(soc!=null){

                    log('转发给用户'+index+':'+tos[index],newMessage);

                    if(userAndRoom[tos[index]]!=null){
                        soc.emit('someBodyCall', newMessage);
                    }else{
                        soc.emit('beMoreCall', newMessage);
                    }
                }
            }
        });

        /**
         * 拒绝通话
         */
        socket.on('refuseCall',function (message) {
            let to = message['to'];
            let from = message['from'];

            let soc=sockets[to];
            let socF=sockets[from];
            socF.emit('refuseCallRev',message)
            soc.emit('beRefuseCall', message);
            log('用户' + from + '拒绝了用户' + to+'的通话请求', message);
        });

        /**
         * 加入房间请求监听
         */
        socket.on('into', function(info) {
            let room=info['room'];
            let userId=info['userId'];
            let type=info['type'];//0单聊，1多聊
            log('请求创建或者加入房间' + room);

            //根据房间名获取房间信息
            let clientsInRoom = io.sockets.adapter.rooms[room];
            //获取房间中客户端数量
            let numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
            log('房间：' + room + ',已经有' + numClients + '名用户进入');

            //多人会话需要判定房间权限
            if(type==1){
                let roomInfo=roomManager[room];
                if(roomInfo!=null&&roomInfo['status']==1){
                    socket.emit('intoErr', '该房间会话已结束');
                    return;
                }
            }
            //将用户绑定房间
            userAndRoom[userId]=room;

            //如果房间没有用户则创建房间
            if (numClients === 0) {
                socket.join(room);

                //将房间信息加入管理池
                let roomInfo={};
                roomInfo['roomName']=room;
                roomInfo['creater']=userId;
                roomInfo['status']=0;
                roomManager[room]=roomInfo;

                log('用户：' + userId + '，创建房间：' + room);
                socket.emit('created', room, userId);
            } else {
                log('用户：' + userId + '，加入房间：' + room);
                io.sockets.in(room).emit('join', room, userId);
                socket.join(room);
                //通话房间处于就绪状态
                io.sockets.in(room).emit('ready');
            }

        });

        /**
         * 申请房间
         */
        socket.on('roompermission',function (info) {
            let from=info['from'];
            let soc=sockets[from];
            log('申请房间',from,new Date().getTime());

            let roomId=uuidv4();

            if(soc!=null){
                soc.emit('roompermissionRev',roomId);
            }

        });

        /**
         * 离开房间请求监听
         */
        socket.on('out', function(info) {
            let room=info['room'];
            let userId=info['userId'];
            log('请求离开房间' + room);
            //根据房间名获取房间信息
            let clientsInRoom = io.sockets.adapter.rooms[room];
            //获取房间中客户端数量
            let numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
            log('房间：' + room + ',已经有' + numClients + '名用户进入');
            try {

                let soc=sockets[userId];

                soc.leave(room,function () {

                    //解除绑定
                    delete userAndRoom[userId];
                    //刷新房间状态
                    clientsInRoom=io.sockets.adapter.rooms[room];
                    numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
                    if(numClients==0){
                        roomManager[room]['status']=1;
                    }

                    io.sockets.in(room).emit('outRoom',room,userId);
                });

            }catch (e) {
                console.error(e);
            }
        });
    });

    Date.prototype.Format = function(fmt) { //author: meizz
        var o = {
            "M+": this.getMonth() + 1, //月份
            "d+": this.getDate(), //日
            "h+": this.getHours(), //小时
            "m+": this.getMinutes(), //分
            "s+": this.getSeconds(), //秒
            "S": this.getMilliseconds() //毫秒
        };
        if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
        for (var k in o)
            if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
        return fmt;
    }

}
module.exports=SOCKET;

